package com.upay.android.controller.fragment;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.codehaus.jackson.type.TypeReference;

import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import com.upay.android.R;
import com.upay.android.controller.adapter.FixedPaymentArrayAdapter;
import com.upay.android.controller.helper.Format;
import com.upay.android.controller.policy.FixedPaymentResultMappingPolicy;
import com.upay.android.core.service.RestService;
import com.upay.android.domain.authentication.AuthenticationToken;
import com.upay.android.domain.group.GroupAccount;
import com.upay.android.domain.payment.FixedPaymentDetail;
import com.upay.android.domain.payment.PaymentDetail;
import com.upay.android.domain.payment.PaymentList;
import com.upay.android.domain.request.ProtectedRequestHeader;
import com.upay.android.domain.request.RequestBody;
import com.upay.android.domain.request.RequestEnvelope;
import com.upay.android.domain.response.EmptyResponse;
import com.upay.android.domain.response.ResponseEnvelope;
import com.upay.android.domain.rest.RestRequest;
import com.upay.android.util.rest.UrlHelper;

public class FixedPaymentFragment extends AbstractFragment {

	/* ---- Constants ---- */

	/* ---- Instance Variables ---- */
	private PaymentList<FixedPaymentDetail> mPaymentList = null;
	private ListView mTransactionsField = null;
    private OnFixedPaymentSelectedListener mCallback;
    private TextView mTransactionTotalField = null;
    private GroupAccount mGroupAccount = null;
	
	/* ---- Constructors ---- */
	
	/* ---- Business Methods ---- */
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getContext().setTitle(R.string.fixed_payment_title);
		setHasOptionsMenu(true);
        mPaymentList = new PaymentList<FixedPaymentDetail>(new ArrayList<FixedPaymentDetail>()); 
	}
		

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_fixed_payment_group_transaction, parent, false);
         
        mTransactionTotalField = (TextView)view.findViewById(R.id.value_fixed_payment_transaction_total);
        mTransactionsField = (ListView)view.findViewById(R.id.list_fixed_payment_transactions);
        mTransactionsField.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
        mTransactionsField.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
            	FixedPaymentDetail paymentDetail = mPaymentList.get(position);
            	FixedPaymentResultMappingPolicy policy = new FixedPaymentResultMappingPolicy(
            		paymentDetail.getTransactionLine(),
            		paymentDetail.getGroupAccount().getUser());
            	mCallback.onPaymentSelected(policy);
            }
        });
        
		getLoaderManager().initLoader(0, null, new FixedPaymentFragment.FixedPaymentLoader());
		updateTransactionTotal();
        return view; 
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    	inflater.inflate(R.menu.fixedpaymentmenu, menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch(item.getItemId()) {
    	case android.R.id.home:
    		getContext().finish();
    		break;
    	case R.id.action_fixed_payment_confirm_transaction:
    		doFinalizeTransaction();
    		break;
    	case R.id.action_fixed_payment_refresh:
    		getLoaderManager().restartLoader(0, null, new FixedPaymentLoader());
    		break;
    	default:
    		return super.onOptionsItemSelected(item);
    	}
    	return true;
    }
    
    private void doFinalizeTransaction() {
    	if (mPaymentList.getTransactionValue().equals(new BigDecimal(0))) {
    		getContext().showValidationErrors("Set at least one Transaction Cost", Gravity.CENTER);
    	} else {
    		getLoaderManager().initLoader(1, null, new FixedPaymentFragment.FixedPaymentSender());
    	}
    }
    
    public void updateTransactionTotal() {
    	refreshTransactionTotal();
    	mTransactionTotalField.setText(Format.format(mPaymentList.getTransactionValue()));
    }
    
    public void refreshTransactionTotal() {
    	BigDecimal transactionTotal = new BigDecimal(0);
    	for (PaymentDetail payment : mPaymentList.getPayments()) {
    		transactionTotal = transactionTotal.add(((FixedPaymentDetail)payment).getTransactionLine().getValue());
    	}
    	mPaymentList.setTransactionValue(transactionTotal);
    }
	
   	/* ---- Getters and Setters ---- */

	public GroupAccount getGroupAccount() {
		return mGroupAccount;
	}

	public void setGroupAccount(GroupAccount groupAccount) {
		this.mGroupAccount = groupAccount;
	}
	
	/* ---- Interfaces ---- */

    // Container Activity must implement this interface
    public interface OnFixedPaymentSelectedListener {
        public void onPaymentSelected(FixedPaymentResultMappingPolicy policy);
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnFixedPaymentSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFixedPaymentSelectedListener");
        }
    }
    
    /* ---- Inner Classes ---- */
    
    private class FixedPaymentLoader implements LoaderCallbacks<ResponseEnvelope<List<FixedPaymentDetail>>> {

    	@Override
    	public Loader<ResponseEnvelope<List<FixedPaymentDetail>>> onCreateLoader(int id, Bundle bundle) {
    		AuthenticationToken authenticationToken = getAuthenticationToken();
    		RequestEnvelope<ProtectedRequestHeader, GroupAccount> requestEnvelope = 
    				new RequestEnvelope<ProtectedRequestHeader, GroupAccount>(
    					new ProtectedRequestHeader(authenticationToken), 
    					new RequestBody<GroupAccount>(mGroupAccount));
    		TypeReference<ResponseEnvelope<List<FixedPaymentDetail>>> typeReference = new TypeReference<ResponseEnvelope<List<FixedPaymentDetail>>>() {};
    		RestRequest<ProtectedRequestHeader, GroupAccount, List<FixedPaymentDetail>> restRequest = 
    				new RestRequest<ProtectedRequestHeader, GroupAccount, List<FixedPaymentDetail>>(
    					UrlHelper.getUrl(getResources(), UrlHelper.GET_FIXED_PAYMENT_DETAILS),
    					requestEnvelope, 
    					typeReference);           	    
    		RestService<ProtectedRequestHeader, GroupAccount, List<FixedPaymentDetail>> restService =
    				new RestService<ProtectedRequestHeader, GroupAccount, List<FixedPaymentDetail>>(
    					getActivity().getApplicationContext(), restRequest);
    		return restService;
    	}
	

    	@Override
    	public void onLoadFinished(Loader<ResponseEnvelope<List<FixedPaymentDetail>>> loader, ResponseEnvelope<List<FixedPaymentDetail>> responseEnvelope) {
    		if (!responseEnvelope.getResponseHeader().getStatus()) {
    			getContext().handleError(responseEnvelope.getResponseBody().getResponseError());
    		} else {
    			mPaymentList.payments.clear();
    			for (FixedPaymentDetail paymentDetail : responseEnvelope.getResponseBody().getResponseObject()) {
    				mPaymentList.add(paymentDetail);
    				if (mPaymentList.getSelectedPayment() == null) {
    					mPaymentList.setSelectedPayment(paymentDetail);
    					paymentDetail.setSelected(Boolean.TRUE);
    				}
    			}
			
    			FixedPaymentArrayAdapter adapter = new FixedPaymentArrayAdapter(getContext(), mPaymentList);
    			mTransactionsField.setAdapter(adapter);
    			updateTransactionTotal();
    		}
    	}

    	@Override
    	public void onLoaderReset(Loader<ResponseEnvelope<List<FixedPaymentDetail>>> loader) {
    	}
	
    } // end class
    
    private class FixedPaymentSender implements LoaderCallbacks<ResponseEnvelope<EmptyResponse>> {

    	@Override
    	public Loader<ResponseEnvelope<EmptyResponse>> onCreateLoader(int id, Bundle bundle) {
    		AuthenticationToken authenticationToken = getAuthenticationToken();
    				
    		RequestEnvelope<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>> requestEnvelope = 
    			new RequestEnvelope<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>>(
    				new ProtectedRequestHeader(authenticationToken), 
    				new RequestBody<PaymentList<FixedPaymentDetail>>(mPaymentList));
    		TypeReference<ResponseEnvelope<EmptyResponse>> typeReference = new TypeReference<ResponseEnvelope<EmptyResponse>>() {};
    		RestRequest<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>, EmptyResponse> restRequest = 
    			new RestRequest<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>, EmptyResponse>(
    				UrlHelper.getUrl(getResources(), UrlHelper.SAVE_FIXED_PAYMENT_DETAILS),
    				requestEnvelope, 
    				typeReference);           	    
    		RestService<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>, EmptyResponse> restService =
    			new RestService<ProtectedRequestHeader, PaymentList<FixedPaymentDetail>, EmptyResponse>(
    				getActivity().getApplicationContext(),
    				restRequest);
    		return restService;
    	}
	

    	@Override
    	public void onLoadFinished(Loader<ResponseEnvelope<EmptyResponse>> loader, ResponseEnvelope<EmptyResponse> responseEnvelope) {
    		if (!responseEnvelope.getResponseHeader().getStatus()) {
    			getContext().handleError(responseEnvelope.getResponseBody().getResponseError());
    		} else {		
        		getContext().finish();
    		}
    	}

    	@Override
    	public void onLoaderReset(Loader<ResponseEnvelope<EmptyResponse>> loader) {
    	}
	
    } // end class
	
}

